//队列配置
#ifndef __FIFO_H__
#define __FIFO_H__
#ifdef __cplusplus
// 作用：确保 C++ 编译器能够正确处理 C 语言编写的代码。
extern "C" {
#endif

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

  //******************************************************************************************
  //!                           配置宏定义
  //******************************************************************************************
// 禁用断言。
// 启用动态内存分配功能，使用系统提供的 malloc 和 free 函数。
#define NDEBUG
#define USE_DYNAMIC_MEMORY //!< 使用系统 malloc/free 函数

#include "stm32f4xx_hal.h"

#define FIFO_ENTER_CRITICAL __disable_irq
#define FIFO_EXIT_CRITICAL __enable_irq
#define FIFO_GET_CPU_SR __get_PRIMASK
#define FIFO_RESTORE_CPU_SR(CPU_SR) __set_PRIMASK(CPU_SR)
#define FIFO_CPU_SR_TYPE register unsigned long

  //******************************************************************************************
  //!                     宏函数
  //******************************************************************************************

  //******************************************************************************************
  //!                           公共类型定义
  //******************************************************************************************

  //! FIFO 内存模型（单字节模式）
  typedef struct
  {
    char *p_start_addr; //!< FIFO 内存池起始地址
    char *p_end_addr;   //!< FIFO 内存池结束地址
    int free_num;       //!< FIFO 剩余容量
    int used_num;       //!< FIFO 中元素的数量
    char *p_read_addr;  //!< FIFO 数据读取索引指针
    char *p_write_addr; //!< FIFO 数据写入索引指针
  } fifo_s_t;

  //! FIFO 内存模型
  typedef struct
  {
    char *p_start_addr; //!< FIFO 内存池起始地址
    char *p_end_addr;   //!< FIFO 内存池结束地址
    int free_num;       //!< FIFO 剩余容量
    int used_num;       //!< FIFO 中元素的数量
    int unit_size;      //!< FIFO 元素大小（单位：字节）
    char *p_read_addr;  //!< FIFO 数据读取索引指针
    char *p_write_addr; //!< FIFO 数据写入索引指针
  } fifo_t;

  //******************************************************************************************
  //!                           公共 API
  //******************************************************************************************

#ifdef USE_DYNAMIC_MEMORY

  //******************************************************************************************
  //
  //! \brief  创建一个新的 FIFO 实例（单字节模式）。
  //! 该函数为 N 个块的 FIFO 元素分配足够的空间，然后返回 FIFO 的指针。
  //!
  //! \param  [in] uint_cnt 是 FIFO 元素的数量。
  //! \retval 成功时返回 FIFO 实例的指针，失败时返回 NULL。
  //!
  //! \note   -# 必须启用 USE_MEMORY_ALLOC 宏，并确保系统有 <stdlib.h> 头文件才能使用此函数。
  //! \note   -# 函数 FIFO_Create 和 FIFO_Destory 必须成对使用。
  //!
  //******************************************************************************************
  fifo_s_t *fifo_s_create(int uint_cnt);

  //******************************************************************************************
  //
  //! \brief  销毁 FIFO 实例（单字节模式）。
  //! 该函数释放内存，然后重新初始化 FIFO 结构体。
  //!
  //! \param  [in] p_fifo 是 FIFO 实例的指针
  //! \retval 无。
  //!
  //! \note   -# 必须启用 USE_MEMORY_ALLOC 宏，并确保系统有 <stdlib.h> 头文件才能使用此函数。
  //
  //******************************************************************************************
  void fifo_s_destroy(fifo_s_t * p_fifo);

#endif // USE_DYNAMIC_MEMORY

  //******************************************************************************************
  //
  //! \brief  初始化一个静态 FIFO 结构体（单字节模式）。
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 实例的指针。
  //! \param  [in] p_base_addr 是预分配内存的基地址，例如数组。
  //! \param  [in] uint_cnt 是 FIFO 元素的数量。
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_s_init(fifo_s_t * p_fifo, void *p_base_addr, int uint_cnt);

  //******************************************************************************************
  //
  //! \brief  将一个元素放入 FIFO（单字节模式）。
  //!
  //! \param  [in]  p_fifo 是有效的 FIFO 指针。
  //! \param  [in]  element 是要放入的数据元素
  //!
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_s_put(fifo_s_t * p_fifo, char element);

  int fifo_s_puts(fifo_s_t * p_fifo, char *p_source, int len);
  int fifo_s_puts_noprotect(fifo_s_t * p_fifo, char *p_source, int len);

  //******************************************************************************************
  //
  //! \brief  从 FIFO 获取一个元素（单字节模式）。
  //!
  //! \param  [in]  p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval FIFO 中的数据元素。
  //
  //******************************************************************************************
  char fifo_s_get(fifo_s_t * p_fifo);
  int fifo_s_gets(fifo_s_t * p_fifo, char *p_dest, int len);
  int fifo_s_gets_noprotect(fifo_s_t * p_fifo, char *p_dest, int len);

  //******************************************************************************************
  //
  //! \brief  预读取 FIFO 中的一个元素（单字节模式）。
  //!
  //! \param  [in]  p_fifo 是有效的 FIFO 指针。
  //! \param  [in]  Offset 是从当前指针偏移的距离。
  //!
  //! \retval FIFO 中的数据元素。
  //
  //******************************************************************************************
  char fifo_s_preread(fifo_s_t * p_fifo, int offset);
  int fifo_s_prereads(fifo_s_t * p_fifo, char *p_dest, int offset, int len);

  //******************************************************************************************
  //
  //! \brief  FIFO 是否为空（单字节模式）？
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval - 非零（真）表示为空。
  //!         - 零（假）表示不为空。
  //
  //******************************************************************************************
  char fifo_s_isempty(fifo_s_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  FIFO 是否已满（单字节模式）？
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval - 非零（真）表示已满。
  //!         - 零（假）表示未满。
  //
  //******************************************************************************************
  char fifo_s_isfull(fifo_s_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  获取 FIFO 中的元素数量（单字节模式）。
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval FIFO 中的元素数量。
  //
  //******************************************************************************************
  int fifo_s_used(fifo_s_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  获取 FIFO 中的空闲空间数量（单字节模式）。
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval FIFO 中的空闲空间数量。
  //
  //******************************************************************************************
  int fifo_s_free(fifo_s_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  清空 FIFO 的内容。
  //!
  //! \param  [in] p_fifo 是有效的 FIFO 指针。
  //!
  //! \retval 成功时返回 0，失败时返回 -1。
  //
  //******************************************************************************************
  void fifo_s_flush(fifo_s_t * p_fifo);
  int fifo_s_discard(fifo_s_t * p_fifo, int len);

  //******************************************************************************************
  //
  //! \brief  创建一个新的 FIFO 实例。
  //! 该函数为 N 个块的 FIFO 元素分配足够的空间，然后返回 FIFO 的指针。
  //!
  //! \param  [in] UnitSize 是 FIFO 元素的大小。
  //! \param  [in] UnitCnt 是 FIFO 元素的数量。
  //! \retval 成功时返回 FIFO 实例的指针，失败时返回 NULL。
  //!
  //! \note   -# 必须启用 USE_MEMORY_ALLOC 宏，并确保系统有 <stdlib.h> 头文件才能使用此函数。
  //! \note   -# 函数 FIFO_Create 和 FIFO_Destory 必须成对使用。
  //!
  //******************************************************************************************
  fifo_t *fifo_create(char unit_size, int unit_cnt);

  //******************************************************************************************
  //
  //! \brief  销毁 FIFO 实例。
  //! 该函数释放内存，然后重新初始化 FIFO 结构体。
  //!
  //! \param  [in] pFIFO 是 FIFO 实例的指针
  //! \retval 无。
  //!
  //! \note   -# 必须启用 USE_MEMORY_ALLOC 宏，并确保系统有 <stdlib.h> 头文件才能使用此函数。
  //
  //******************************************************************************************
  void fifo_destory(fifo_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  初始化一个静态 FIFO 结构体。
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 实例的指针。
  //! \param  [in] pBaseAddr 是预分配内存的基地址，例如数组。
  //! \param  [in] UnitSize 是 FIFO 元素的大小。
  //! \param  [in] UnitCnt 是 FIFO 元素的数量。
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_init(fifo_t * p_fifo, void *p_base_addr, char unit_size, int unit_cnt);

  //******************************************************************************************
  //
  //! \brief  将一个元素放入 FIFO。
  //!
  //! \param  [in]  pFIFO 是有效的 FIFO 指针。
  //! \param  [in]  pElement 是要放入的元素的地址
  //!
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_put(fifo_t * p_fifo, void *p_element);
  int fifo_put_noprotect(fifo_t * p_fifo, void *p_element);
  //******************************************************************************************
  //
  //! \brief  从 FIFO 获取一个元素。
  //!
  //! \param  [in]  pFIFO 是有效的 FIFO 指针。
  //! \param  [out] pElement 是要获取的元素的地址
  //!
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_get(fifo_t * p_fifo, void *p_element);
  int fifo_get_noprotect(fifo_t * p_fifo, void *p_element);

  //******************************************************************************************
  //
  //! \brief  预读取 FIFO 中的一个元素。
  //!
  //! \param  [in]  pFIFO 是有效的 FIFO 指针。
  //! \param  [in]  Offset 是从当前指针偏移的距离。
  //! \param  [out] pElement 是要获取的元素的地址
  //!
  //! \retval 成功时返回 0，否则返回 -1。
  //
  //******************************************************************************************
  int fifo_pre_read(fifo_t * p_fifo, char offset, void *p_element);

  //******************************************************************************************
  //
  //! \brief  FIFO 是否为空？
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 指针。
  //!
  //! \retval - 非零（真）表示为空。
  //!         - 零（假）表示不为空。
  //
  //******************************************************************************************
  int fifo_is_empty(fifo_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  FIFO 是否已满？
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 指针。
  //!
  //! \retval - 非零（真）表示已满。
  //!         - 零（假）表示未满。
  //
  //******************************************************************************************
  int fifo_is_full(fifo_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  获取 FIFO 中的元素数量。
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 指针。
  //!
  //! \retval FIFO 中的元素数量。
  //
  //******************************************************************************************
  int fifo_used(fifo_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  获取 FIFO 中的空闲空间数量。
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 指针。
  //!
  //! \retval FIFO 中的空闲空间数量。
  //
  //******************************************************************************************
  int fifo_free(fifo_t * p_fifo);

  //******************************************************************************************
  //
  //! \brief  清空 FIFO 的内容。
  //!
  //! \param  [in] pFIFO 是有效的 FIFO 指针。
  //!
  //! \retval 成功时返回 0，失败时返回 -1。
  //
  //******************************************************************************************
  int fifo_flush(fifo_t * p_fifo);

#ifdef __cplusplus
}
#endif

#endif // __FIFO_H__